package fr.resasante.ejb.service.helper;

import java.io.StringWriter;
import java.util.Locale;
import java.util.Properties;
import java.util.ResourceBundle;

import javax.annotation.Resource;
import javax.mail.Address;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.naming.NamingException;

import net.htmlparser.jericho.Renderer;
import net.htmlparser.jericho.Segment;
import net.htmlparser.jericho.Source;

import org.apache.commons.lang.StringUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.jboss.logging.Logger;

import fr.resasante.ejb.dto.User;
import fr.resasante.ejb.util.Utf8ResourceBundle;
import fr.resasante.exception.SystemException;
import fr.resasante.utils.PropertiesUtils;

/**
 * Class for getting system properties
 * 
 * @author GEFFROY-DE-VILLEBLAN
 * 
 */
public final class EmailHelper {
	@Resource(mappedName = "java:jboss/mail/Default")
	private Session mailSession;

	/**
	 * HTML content type
	 */
	final private static String HTML = "text/html";

	/**
	 * Plain text content type
	 */
	final private static String PLAIN = "text/plain";

	/**
	 * Encoding
	 */
	final private static String CHARSET = "UTF-8";

	/**
	 * Confirm account template name
	 */
	final private static String CONFIRMATION_TPL = "confirm_account";

	/**
	 * Retrieve account template name
	 */
	final private static String RETRIEVE_ACCOUNT_TPL = "retrieve_account";

	/**
	 * class instance
	 */
	private static volatile EmailHelper instance = null;

	/**
	 * Logger for the class
	 */
	private static final Logger logger = Logger.getLogger(EmailHelper.class.getName());

	/**
	 * Method returning a Singleton class instance
	 * 
	 * @return Singleton instance
	 * @throws NamingException
	 */
	public final static EmailHelper getInstance() {
		if (EmailHelper.instance == null) {
			synchronized (EmailHelper.class) {
				if (EmailHelper.instance == null) {
					EmailHelper.instance = new EmailHelper();
				}
			}
		}
		return EmailHelper.instance;
	}

	/**
	 * Constructor
	 */
	private EmailHelper() {
		super();
	}

	/**
	 * Get a body part of an email
	 * 
	 * @param filename
	 *            The template file
	 * @param contentType
	 *            The content type
	 * @return The body part
	 * @throws MessagingException
	 */
	private BodyPart getFileBodyPart(VelocityContext context, String filename,
			String contentType) throws MessagingException {
		filename = "fr/resasante/email/" + filename;
		// get and initialize an engine
		final VelocityEngine ve = new VelocityEngine();

		final Properties p = new Properties();
		p.setProperty("resource.loader", "class");
		p.setProperty("class.resource.loader.description",
				"Velocity Classpath Resource Loader");
		p.setProperty("class.resource.loader.class",
				"org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");

		ve.init(p);
		// get the Template
		final Template t = ve.getTemplate(filename, CHARSET);
		// render the template into a StringWriter
		final StringWriter writer = new StringWriter();
		t.merge(context, writer);
		final BodyPart bp = new MimeBodyPart();

		// get the HTML text
		final String htmlText = writer.toString();

		final Source htmlSource = new Source(htmlText);
		final Segment htmlSeg = new Segment(htmlSource, 0, htmlText.length());
		final Renderer htmlRend = new Renderer(htmlSeg);

		if (HTML.equals(contentType)) {
			bp.setContent(htmlText, contentType + "; charset=" + CHARSET);
		} else {
			bp.setContent(htmlRend.toString(), contentType + "; charset=" + CHARSET);
		}
		return bp;
	}

	/**
	 * Get a multipart email content
	 * 
	 * @param basename
	 *            The base of the file without the language and the extension
	 * @param locale
	 *            The locale
	 * @return The multipart message
	 * @throws MessagingException
	 */
	private Multipart getMultipart(VelocityContext context, String basename, Locale locale)
			throws MessagingException {
		final Multipart mp = new MimeMultipart("alternative");

		final String filename = basename + "_" + locale.getLanguage() + ".html";

		// Get the HTML
		final BodyPart bp1 = getFileBodyPart(context, filename, HTML);
		mp.addBodyPart(bp1);

		// Get with HTML stripped
		final BodyPart bp2 = getFileBodyPart(context, filename, PLAIN);
		mp.addBodyPart(bp2);

		return mp;
	}

	/**
	 * Init vars for the template
	 * 
	 * @param user
	 *            the user object
	 * @return The context containing vars
	 */
	private VelocityContext initVelocityContext(User user) {
		final VelocityContext context = new VelocityContext();
		context.put("title", PropertiesUtils.getInstance().getProperty("site.title"));
		context.put("siteUrl", StringUtils.chomp(
				PropertiesUtils.getInstance().getProperty("dynamic.url"), "/"));
		context.put("staticUrl", StringUtils.chomp(
				PropertiesUtils.getInstance().getProperty("statics.url"), "/"));
		context.put("user", user);
		return context;
	}

	/**
	 * Send a confirmation by mail
	 * 
	 * @param user
	 *            The user object
	 * @param basename
	 *            the template basename
	 * @param locale
	 */
	public void sendConfirmationAccountEmail(User user, Locale locale) {
		sendEmail(user, CONFIRMATION_TPL, locale);
	}

	/**
	 * Send an email
	 * 
	 * @param user
	 *            the user object
	 * @param basename
	 *            the basename of the template
	 * @param locale
	 *            the locale
	 */
	private void sendEmail(User user, String basename, Locale locale) {
		logger.info("Starting sending the email based on the template " + basename);
		final ResourceBundle bundle = Utf8ResourceBundle.getBundle("messages", locale);
		try {
			final MimeMessage m = new MimeMessage(mailSession);
			final Address from = new InternetAddress(PropertiesUtils.getInstance()
					.getProperty("email.from"));
			final Address[] to = new InternetAddress[] { new InternetAddress(user.getMail()) };
			m.setFrom(from);
			m.setRecipients(Message.RecipientType.TO, to);
			m.setSubject(bundle.getString("mail.subject." + basename));
			m.setSentDate(new java.util.Date());
			// Create an "Alternative" Multipart message
			final VelocityContext context = initVelocityContext(user);
			m.setContent(getMultipart(context, basename, locale));
			Transport.send(m);
			logger.info("Email based on the template " + basename + " sent");
		} catch (final MessagingException e) {
			throw new SystemException("Unable to send the email based on the template "
					+ basename, e);
		}
	}

	/**
	 * Send a confirmation by mail
	 * 
	 * @param user
	 *            The user object
	 * @param basename
	 *            the template basename
	 * @param locale
	 */
	public void sendRetrieveAccountEmail(User user, Locale locale) {
		sendEmail(user, RETRIEVE_ACCOUNT_TPL, locale);
	}
}